package com.abl.service.system.impl;

import com.abl.common.cache.CacheKey;
import com.abl.common.cache.CacheService;
import com.abl.common.mybatis.dao.Dao;
import com.abl.common.mybatis.model.Dnt;
import com.abl.common.mybatis.strengthen.Wrapper;
import com.abl.domain.model.AblError;
import com.abl.domain.model.Param;
import com.abl.common.util.StringKit;
import com.abl.common.util.coll.ArrayKit;
import com.abl.service.system.SysMenuService;
import com.abl.service.system.SysService;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

/**
 * 菜单表实现
 */
@Slf4j
@Service
public class SysMenuServiceImpl implements SysMenuService {
    @Autowired
    private Dao dao;

    @Autowired
    private CacheService cache;

    @Autowired
    private SysService system;

    //新增
    @Override
    public boolean add(Param<JSONObject> param) {
        //校验名称重复
        String name = param.getString("name");
        String pname = param.getString("pname");
        Wrapper<Object> qw = new Wrapper<>();
        qw.eq("d_s", 0);
        qw.eq("name", name);
        qw.eq("pname", pname);
        long sys_api = dao.count("sys_menu", qw);
        if (sys_api > 0) throw new AblError("操作失败：菜单名称 【" + pname + "/" + name + "】 已经存在");

        List<String> keys = Arrays.asList("bre_icon_is_show", "bre_is_show", "bre_title_is_show", "cache_status", "component_path", "icon", "ids", "level", "link_type", "link_url", "ln_key", "menu_is_show", "name", "param", "path", "permission", "pid", "pname", "sort", "tab_icon_is_show", "tab_is_close", "tab_is_refresh", "tab_is_show", "tab_title_is_show", "type");
        Dnt dnt = Dnt.createInsert(param.getJSONObject(keys));
        //遍历树结构
        JSONArray ids = getTreeIds(dnt.getString("id"), dnt.getString("pid"));
        dnt.set("ids", ids.toString());//树结构
        dnt.set("level", ids.size());//层级
        dao.insert("sys_menu", dnt);

        //更新pid不为0的父节点，更新子节点数+1
        updateParentChildrenCount(param.getString("pid"));

        return true;

        //        if (sys_menu == 1) {
        //            Wrapper<Object> qw = new Wrapper<>();
        //            qw.eq("d_s", 0);
        //            qw.ne("id", parse.getString("id"));
        //            qw.eq("pid", parse.getString("id"));
        //            long count = dao.count("sys_menu", qw);
        //            Dnt d = new Dnt();
        //            d.set("has_children", count > 0 ? 1 : null);
        //            Wrapper<Object> uw = new Wrapper<>();
        //            uw.eq("id", parse.getString("id"));
        //            long sys_menu1 = dao.update("sys_menu", d, uw);
        //        }
    }

    //根据ID和PID查库，返回树结构JSON数组 ["PID-001","PID-002","ID"]
    private JSONArray getTreeIds(String id, Object pid) {
        JSONArray treeIds = new JSONArray();
        treeIds.add(id);
        if (!"0".equals(pid)) {
            do {
                Wrapper<Object> qw = new Wrapper<>();
                qw.eq("id", pid);
                Dnt menu = dao.selectOneOrigin("select id,pid from sys_menu", qw);
                if (menu != null) {
                    pid = menu.getString("pid");
                    treeIds.add(0, menu.getString("id"));
                }
            } while (pid != null && !pid.toString().equals("0"));
        }
        return treeIds;
    }

    //删除
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean del(Param<JSONObject> param) {
        ArrayList<Object> ids = param.getList("ids");

        //检查是否存在关联
        if (StringKit.isBlank(param.getString("type"))) {
            Wrapper<Object> wrapper = new Wrapper<>();
            wrapper.in("menu_id", ids);
            long sys_link_role_menu1 = dao.count("sys_link_role_menu", wrapper);
            if (sys_link_role_menu1 > 0) {
                throw new AblError("操作失败：菜单ID {0} 已被使用", ids);
            }
        }

        //汇总待删除IDS(只要ids字段包含【"id"】)
        HashSet<Object> delIds = new HashSet<>();
        for (Object id : ids) {
            Wrapper<Object> wrapper = new Wrapper<>();
            wrapper.select("id");
            wrapper.eq("d_s", 0);
            wrapper.like("ids", "\"" + id + "\"");
            delIds.addAll(dao.listObj("sys_menu", wrapper, String.class));
        }

        //逻辑删除
        if (ArrayKit.isNotBlank(delIds)) {
            Wrapper<Object> uw = new Wrapper<>();
            uw.in("id", delIds);
            uw.set("d_s", 1);
            long sys_menu = dao.update("sys_menu", uw);

            //删除角色资源
            uw = new Wrapper<>();
            uw.in("menu_id", delIds);
            long sys_link_role_menu = dao.delete("sys_link_role_menu", uw);
        }

        return true;
    }

    //修改
    @Override
    public boolean edit(Param<JSONObject> param) {
        //检验路径
//        {
//            String sys_path = param.getString("path");
//            Wrapper<Object> qw = new Wrapper<>();
//            qw.eq("d_s", 0);
//            qw.eq("path", sys_path);
//            qw.ne("id", param.getString("id"));
//            qw.ne("path", "#");
//            long sys_api = dao.count("sys_menu", qw);
//            if (sys_api > 0) throw new AError("操作失败：地址 【" + sys_path + "】 已经存在");
//        }

        //校验名称重复
        String name = param.getString("name");
        String pname = param.getString("pname");
        Wrapper<Object> qw = new Wrapper<>();
        qw.eq("d_s", 0);
        qw.eq("name", name);
        qw.eq("pname", pname);
        qw.ne("id", param.getString("id"));
        long sys_api = dao.count("sys_menu", qw);
        if (sys_api > 0) throw new AblError("操作失败：菜单名称 【" + name + "】 已经存在");
        if (param.getString("id").equals(param.getString("pid"))) throw new AblError("操作失败：当前所选上级目录与自身目录相同，请更换上级目录。");

        //

        List<String> keys = Arrays.asList("id", "link_url", "level", "desc", "name", "icon", "pname", "path", "sort", "pid", "type", "ln_key", "menu_is_show", "tab_is_show", "tab_is_close", "tab_is_refresh", "tab_title_is_show", "tab_icon_is_show", "bre_is_show", "bre_title_is_show", "bre_icon_is_show", "link_type", "param", "component_path");
        Dnt dnt = Dnt.createUpdate(param.getJSONObject(keys));

        //查询树结构
        JSONArray ids = getTreeIds(dnt.getString("id"), dnt.getString("pid"));
        dnt.set("ids", ids.toString());
        //层级
        dnt.set("level", ids.size());
        //更新当前节点数据
        dao.updateById("sys_menu", dnt);

        //更新pid不为0的父节点，更新子节点数+1
        updateParentChildrenCount(param.getString("pid"));

        return true;
    }

    //更新pid不为0的父节点，更新子节点数+1
    private void updateParentChildrenCount(String pid) {
        if (StringKit.isNotBlank(pid) && !pid.equals("0")) {
            Wrapper<Object> qw = new Wrapper<>();
            qw.eq("d_s", 0);
            qw.ne("pid", 0);
            qw.eq("pid", pid);
            long first_children_count = dao.count("sys_menu", qw);

            qw = new Wrapper<>();
            qw.eq("id", pid);
            qw.set("first_children_count", first_children_count);
            dao.update("sys_menu", qw);
        }
    }

    //查询集合
    @Override
    public List<Dnt> list(Param<JSONObject> param) {
        var sys_name = param.getString("name");
        var sys_path = param.getString("path");
        var type = param.getString("type");
        var sys_link_type = param.getString("link_type");
        var sys_menu_is_show = param.getString("menu_is_show");

        Wrapper<Object> qw = new Wrapper<>();
        qw.eq("d_s", 0);
        qw.eq(StringKit.isNotBlank(param.getString("id")), "id", param.getString("id"));
        qw.eq(StringKit.isNotBlank(type), "type", type);
        qw.eq(StringKit.isNotBlank(sys_link_type), "link_type", sys_link_type);
        qw.eq(StringKit.isNotBlank(sys_menu_is_show), "menu_is_show", sys_menu_is_show);
        qw.like(StringKit.isNotBlank(sys_name), "name", sys_name);
        qw.like(StringKit.isNotBlank(sys_path), "path", sys_path);
        qw.orderByAsc("sort");
        return dao.list("sys_menu", qw);
    }

    //模糊查询条件下拉列表
    @Override
    public List<Dnt> searchInput(Param<JSONObject> param) {
        String sys_name = param.getOrDefault("name", "") + "";
        String sys_path = param.getOrDefault("path", "") + "";

        Wrapper<Object> qw = new Wrapper<>();
        qw.eq("d_s", 0);
        qw.last(" limit 30 ");

        if (StringKit.isNotBlank(sys_name)) {
            qw.select("name");
            qw.like("name", sys_name);
            qw.groupBy("name");
            return dao.list("sys_menu", qw);
        }

        if (StringKit.isNotBlank(sys_path)) {
            qw.select("path");
            qw.like("path", sys_path);
            qw.groupBy("path");
            return dao.list("sys_menu", qw);
        }

        return new ArrayList<>();
    }

    @Override
    public List<Dnt> children(Param<JSONObject> param) {
        String pid = param.getString("pid");
        Wrapper<Object> qw = new Wrapper<>();
        qw.eq("d_s", 0);
        qw.eq("pid", pid);
        return dao.list("sys_menu", qw);
    }

    //菜单功能列表
    @Override
    public List<Dnt> funList(Param<JSONObject> param) {
        String menuId = param.getString("menuId");
        String sys_request_url = param.getString("request_url");
        String sys_type = param.getString("type");
        String sys_name = param.getString("name");

        Wrapper<Object> qw = new Wrapper<>();
        qw.eq("d_s", 0);
        qw.eq("menu_id", menuId);
        qw.eq(StringKit.isNotBlank(sys_type), "type", sys_type);
        qw.like(StringKit.isNotBlank(sys_request_url), "request_url", sys_request_url);
        qw.like(StringKit.isNotBlank(sys_name), "name", sys_name);
        qw.orderByAsc("sort");

        return dao.list("sys_menu_fun", qw);
    }

    //新增菜单功能
    @Override
    public long funAdd(Param<JSONObject> param) {
        //检验重复
        String name = param.getString("name");
        String menuId = param.getString("menuId");

        Wrapper<Object> qw = new Wrapper<>();
        qw.eq("d_s", 0);
        qw.eq("name", name);
        qw.eq("menu_id", menuId);
        long sys_api = dao.count("sys_menu_fun", qw);
        if (sys_api > 0) throw new AblError("操作失败：资源 【" + name + "】 已经存在");

        JSONArray apis = param.getJSONArray("apis");
        Object des = param.getOrDefault("desc", "");
        String sort = param.getString("sort");

        Dnt dnt = Dnt.createInsert();
        dnt.set("name", name);
        dnt.set("menu_id", menuId);
        dnt.set("desc", des);
        dnt.set("sort", sort);
        dnt.set("apis", apis.toString());
        return dao.insert("sys_menu_fun", dnt);
    }

    //删除菜单功能
    @Override
    public boolean funDel(Param<JSONObject> param) {
        ArrayList<Object> funIds = param.getList("ids");
        Wrapper<Object> uw = new Wrapper<>();
        uw.set("d_s", 1);
        uw.in("id", funIds);
        dao.update("sys_menu_fun", uw);

        //清除角色资源关联缓存
        for (Object funId : funIds) {
            deleteLinkRoleCache(funId);
        }

        return true;
    }

    //编辑菜单功能
    @Override
    public boolean funEdit(Param<JSONObject> param) {
        //检验重复
        String funId = param.getString("id");
        String funName = param.getString("name");
        String menuId = param.getString("menuId");

        Wrapper<Object> qw = new Wrapper<>();
        qw.eq("d_s", 0);
        qw.eq("name", funName);
        qw.eq("menu_id", menuId);
        qw.ne("id", funId);
        long sys_api = dao.count("sys_menu_fun", qw);
        if (sys_api > 0) throw new AblError("操作失败：资源 【" + funName + "】 已经存在");

        //保存变更
        Dnt dnt = Dnt.createUpdate();
        dnt.set("id", funId);
        dnt.set("menu_id", menuId);
        dnt.set("apis", param.getJSONArray("apis").toString());
        dnt.set("name", funName);
        dnt.set("desc", param.getString("desc"));
        dnt.set("sort", param.getString("sort"));
        dao.updateById("sys_menu_fun", dnt);

        deleteLinkRoleCache(funId);

        return true;
    }

    @Override
    public Dnt funInfo(Param<JSONObject> param) {
        String id = param.getString("id");
        Wrapper<Object> qw = new Wrapper<>();
        qw.eq("d_s", 0);
        qw.eq("id", id);
        Dnt sys_menu_fun = dao.selectOne("sys_menu_fun", qw);
        if (sys_menu_fun != null) {
            qw = new Wrapper<>();
            String menu_id = sys_menu_fun.getString("menu_id");
            qw.eq("d_s", 0);
            qw.eq("id", menu_id);
            Dnt menu = dao.selectOne("sys_menu", qw);
            sys_menu_fun.set("menu", menu);
        }
        return sys_menu_fun;
    }

    //清空关联角色缓存
    private void deleteLinkRoleCache(Object funId) {
        Wrapper<Object> qw = new Wrapper<>();
        qw.select("role_id");
        qw.eq("menu_fun_id", funId);
        List<Object> roleIds = dao.listObj("sys_link_role_menu_fun", qw);
        for (Object roleId : roleIds) {
            //清空关联角色缓存
            cache.delete(CacheKey.LINK_ROLE_API.key() + roleId);
        }
    }

}
